module RSpec
  module Matchers
    # #persist matcher defined here
    # @example
    #     expect do
    #       #routine
    #     end.to persist.at_least(3) # or 3.seconds if you use ActiveSupport
    module Timeout
      def self.included(*args)
        RSpec::Matchers.define :persist do
          supports_block_expectations
          @should_complete_block = nil

          chain :at_least do |time|
            @time = time
            @should_complete_block = false
          end

          chain :at_most do |time|
            @time = time
            @should_complete_block = true
          end

          match do |actual|
            fail "Block expected, got #{actual.class}" unless actual.respond_to? :call 
            fail "Expected 'persist.at_least(<seconds>)' or 'persist.at_most(<seconds>)'" if @should_complete_block.nil?
            begin
              ::Timeout.timeout(@time, &actual)
              @block_complete = true
            rescue ::Timeout::Error
              @block_complete = false
            end
            @block_complete == @should_complete_block
          end
        end
      end
    end
  end
end
